using Engine;
using Game;

namespace SCIENEW {
    public static class DevicesUtils {

        public static readonly Vector3[] m_faceToVector3 = [
            new Vector3(0.0f, 0.0f, 1f),
            new Vector3(1f, 0.0f, 0.0f),
            new Vector3(0.0f, 0.0f, 1f),
            new Vector3(1f, 0.0f, 0.0f),
            new Vector3(0.0f, 1f, 0.0f),
            new Vector3(0.0f, 1f, 0.0f)
        ];

        /// <summary>
        /// 获取机器特殊值
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static int GetInnerData(int value) => Terrain.ExtractData(value) & 0b111;

        /// <summary>
        /// 获取机器索引
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static int GetDeviceIndex(int value) => Terrain.ExtractData(value) >> 3;

        /// <summary>
        /// 通过坐标点获取某处的机器
        /// </summary>
        /// <param name="subsystemTerrain"></param>
        /// <param name="position"></param>
        /// <param name="blockValue"></param>
        /// <returns></returns>
        public static DeviceBlock? FindDevice(SubsystemTerrain subsystemTerrain, Point3 position, out int blockValue) {
            blockValue = subsystemTerrain.Terrain.GetCellValueFast(position.X, position.Y, position.Z);
            if (BlocksManager.Blocks[Terrain.ExtractContents(blockValue)] is BaseDeviceBlock) {
                return DevicesBlockManager.GetDevice(blockValue);
            }
            return null;
        }

        public static int SetInnerData(int value, int innerData) {
            if (innerData < 0
                || innerData > 0b111)
                throw new OverflowException($"{innerData}超出了界限");
            int data = Terrain.ExtractData(value);
            data &= -8;//清除后三位
            data |= innerData;
            return Terrain.ReplaceData(value, data);
        }

        /// <summary>
        /// 根据ComponentMiner判断玩家放方块朝向（4向）
        /// </summary>
        /// <param name="componentMiner"></param>
        /// <returns></returns>
        public static int GetDirectionXZ(ComponentMiner componentMiner, bool isOpposite = false)
        {
            Vector3 forward = componentMiner.ComponentCreature.ComponentCreatureModel.EyeRotation.GetForwardVector();
            float num = Vector3.Dot(forward, Vector3.UnitZ);
            float num2 = Vector3.Dot(forward, Vector3.UnitX);
            float num3 = Vector3.Dot(forward, -Vector3.UnitZ);
            float num4 = Vector3.Dot(forward, -Vector3.UnitX);
            float max = MathUtils.Max(num, num2, num3, num4);
            int face = 0;
            if (num == max) face = 2;
            if (num2 == max) face = 3;
            if (num3 == max) face = 0;
            if (num4 == max) face = 1;
            return isOpposite ? CellFace.OppositeFace(face) : face;
        }

        /// <summary>
        /// 根据ComponentMiner判断玩家放方块朝向（6向）
        /// </summary>
        /// <param name="componentMiner"></param>
        /// <param name="isOpposite"></param>
        /// <returns></returns>
        public static int GetDirectionXYZ(ComponentMiner componentMiner, bool isOpposite = false)
        {
            Vector3 forward = componentMiner.ComponentCreature.ComponentCreatureModel.EyeRotation.GetForwardVector();
            float num = Vector3.Dot(forward, Vector3.UnitZ),
                num2 = Vector3.Dot(forward, Vector3.UnitX),
                num3 = Vector3.Dot(forward, -Vector3.UnitZ),
                num4 = Vector3.Dot(forward, -Vector3.UnitX),
                num5 = Vector3.Dot(forward, Vector3.UnitY),
                num6 = Vector3.Dot(forward, -Vector3.UnitY),
                num7 = MathUtils.Min(MathUtils.Min(num, num2, num3), MathUtils.Min(num4, num5, num6));
            int face = 0;
            if (num == num7) face = 0;
            if (num2 == num7) face = 1;
            if (num3 == num7) face = 2;
            if (num4 == num7) face = 3;
            if (num5 == num7) face = 4;
            if (num6 == num7) face = 5;
            return isOpposite ? CellFace.OppositeFace(face) : face;
        }

        /// <summary>
        /// 获得某个面的相邻两个面，适用于4向机器
        /// </summary>
        /// <param name="face"></param>
        /// <param name="face1"></param>
        /// <param name="face2"></param>
        public static void GetSideFaceOfXZ(int face, out int face1, out int face2) {
            face1 = -1;
            face2 = -1;
            switch (face) {
                case 0:
                    face1 = 1;
                    face2 = 3;
                    break;
                case 1:
                    face1 = 0;
                    face2 = 2;
                    break;
                case 2:
                    face1 = 1;
                    face2 = 3;
                    break;
                case 3:
                    face1 = 2;
                    face2 = 0;
                    break;
            }
        }

        public static Vector3 NormalToVector3(int faceNormal) {
            switch (faceNormal) {
                case 0:
                case 2: return new Vector3(1, 1, 0);
                case 1:
                case 3: return new Vector3(0, 1, 1);
                case 4:
                case 5: return new Vector3(1, 0, 1);
                default: return Vector3.Zero;
            }
        }

        public static Vector3 FaceToVector3Abs(int face) => m_faceToVector3[face];
    }
}